<?php
/** @noinspection PhpUnused */
declare(strict_types=1);

namespace app\shop\controller;

use app\admin\library\module\Server;
use app\common\library\Upload;
use app\shop\enums\sms\SmsTemplateCode;
use app\shop\enums\user\UserStatus;
use app\shop\exception\FailException;
use app\shop\exception\ParamsErrorException;
use app\shop\library\ShopAuth;
use app\shop\library\ShopHelper;
use app\shop\model\user\UserModel;
use ba\Captcha;
use ba\ClickCaptcha;
use ba\Tree;
use modules\sms\Sms as smsLib;
use think\facade\Db;
use think\facade\Event;
use think\facade\Validate;
use think\response\Json;
use Throwable;

class CommonController extends BaseController
{
    protected array $noNeedLogin = ['setting', 'agreements', 'sendSmsCode', 'area'];

    /**
     * 文件上传
     * @return Json
     * @throws FailException
     */
    public function upload(): Json
    {
        $file   = request()->file('file');
        $driver = request()->param('driver', 'local');
        $topic  = request()->param('topic', 'default');
        try {
            $upload     = new Upload();
            $attachment = $upload
                ->setFile($file)
                ->setDriver($driver)
                ->setTopic($topic)
                ->upload();
            unset($attachment['create_time'], $attachment['quote']);
        } catch (Throwable $e) {
            throw new FailException('上传失败,请稍后再试', null, $e);
        }

        return $this->success($attachment);
    }

    /**
     * 配置信息
     * @return Json
     * @throws Throwable
     */
    public function setting(): Json
    {
        $agreements = ShopHelper::get_setting_group('agreement_group');
        $uploadSetting = get_upload_config();

        $ini = Server::getIni(root_path('modules/joyshop'));

        $result = [
            'version'        => $ini['version'],
            'agreement'      => [
                'user_agreement'     => $agreements['user_agreement'],
                'privacy_agreement'  => $agreements['privacy_agreement'],
                'about_us_agreement' => $agreements['about_us_agreement'],
                'orderprocess' => $agreements['orderprocess'],
                'buyorder' => $agreements['buyorder'],
                'customer_service' => $agreements['customer_service'],
                'sparring' => $agreements['sparring'],
            ],
            'upload_setting' => $uploadSetting,
            'cdn_url'        => config('buildadmin.cdn_url'),
            'h5_domain'      => ShopHelper::full_h5_url(),
            'customer_service_telephone' => $agreements['customer_service_telephone']
        ];

        return $this->success($result);
    }

    /**
     * 获取地区数据
     * @return Json
     */
    public function area(): Json
    {
        $data = Tree::instance()->assembleChild(ShopHelper::get_all_area());

        return $this->success($data);
    }

    /**
     * 发送短信
     * @return Json
     * @throws FailException
     * @throws ParamsErrorException
     * @throws Throwable
     */
    public function sendSmsCode(): Json
    {
        if (!shopHelper::installed_module('sms')) {
            throw new ParamsErrorException('短信功能未开启，请联系管理员');
        }

        $params   = request()->post();
        $validate = Validate::rule([
            'mobile'        => 'require|mobile',
            'template_code' => 'require',
            'captcha_id'    => 'require',
            'captcha_info'  => 'require'
        ])->message([
            'mobile'        => '手机号格式错误',
            'template_code' => '缺少模板参数',
            'captcha_id'    => '验证码参数有误',
            'captcha_info'  => '验证码错误'
        ]);
        if (!$validate->check($params)) {
            throw new ParamsErrorException($validate->getError());
        }

        // 检查验证码
        $captchaObj = new Captcha();
        if ($params['click']) {  // 点选验证码
            $checked = (new ClickCaptcha())->check($params['captcha_id'], $params['captcha_info']);
        } else {
            $checked = $captchaObj->check($params['captcha_info'], $params['captcha_id']);
        }

        if (!$checked) {
            throw new ParamsErrorException('验证码错误');
        }

        // 检查频繁发送
        $captcha = $captchaObj->getCaptchaData($params['mobile'] . $params['template_code']);
        if ($captcha && time() - $captcha['create_time'] < 60) {
            throw new ParamsErrorException('验证码发送频繁，请稍后再试');
        }

        // 检查号码占用
        $userInfo = UserModel::where('mobile', $params['mobile'])->findOrEmpty();
        $userAuth = ShopAuth::instance()->getUser();
        isset($userInfo->status) && $userInfo->status == UserStatus::DISABLE && throw new ParamsErrorException('账号状态异常，请联系客服');
        switch ($params['template_code']) {
            case SmsTemplateCode::USER_REGISTER:
                if (!$userInfo->isEmpty()) {
                    throw new ParamsErrorException('手机号已注册，请直接登录');
                }
                $userInfo = UserModel::where('username', $params['username'])->findOrEmpty();
                if (!$userInfo->isEmpty()) {
                    throw new ParamsErrorException('用户名已被使用，请更换');
                }
                break;
            case SmsTemplateCode::USER_CHANGE_MOBILE:
                if (!$userInfo->isEmpty()) {
                    throw new ParamsErrorException('手机号已被绑定，请更换');
                }
                break;
            case SmsTemplateCode::USER_RETRIEVE_PWD:
                if (isset($userAuth['mobile']) && $params['mobile'] !== $userAuth['mobile']) {
                    throw new ParamsErrorException('请使用当前账户绑定的手机号');
                }
                if ($userInfo->isEmpty()) {
                    throw new ParamsErrorException('手机号未注册，请注册后再使用');
                }
                break;
            case SmsTemplateCode::USER_MOBILE_VERIFY:
                if ($userInfo->isEmpty()) {
                    throw new ParamsErrorException('手机号未注册，请注册后再使用');
                }
                $password = request()->post('password', '');
                if ($password && $userInfo['password'] !== encrypt_password($password, $userInfo['salt'])) {
                    throw new ParamsErrorException('用户密码错误');
                }
                break;
            default:
                $template = Db::name('sms_template')->where('code', $params['template_code'])->findOrEmpty();
                if ($template->isEmpty()) {
                    throw new ParamsErrorException('短信模板参数错误');
                }
        }

        // 只返回测试验证码给前端，不发送短信
        if (env('SMS_TEST', false)) {
            $captchaId = $params['mobile'] . $params['template_code'];
            $code      = (new Captcha())->create($captchaId, '1111');
            throw new ParamsErrorException("验证码为：$code (仅测试)");
        }

        // 监听短信模板分析完成
        Event::listen('TemplateAnalysisAfter', function ($templateData) use ($params) {
            $captchaId = $params['mobile'] . $params['template_code'];
            // 存储验证码
            if (array_key_exists('code', $templateData['variables'])) {
                (new Captcha())->create($captchaId, $templateData['variables']['code']);
            }
            if (array_key_exists('alnum', $templateData['variables'])) {
                (new Captcha())->create($captchaId, $templateData['variables']['alnum']);
            }
        });

        try {
            smsLib::send($params['template_code'], $params['mobile']);
        } catch (Throwable $e) {
            throw new ParamsErrorException('验证码发送失败，请稍后再试', null, $e);
        }

        return $this->success('验证码已发送，请查收!');
    }
}